package com.yisu.expressway.ewf.common.web;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2016/1/26.
 */
public class HttpWebClient {

    public static final Logger              logger                = LoggerFactory.getLogger(HttpWebClient.class);

    public static final int                 DEFAULT_MAX_PER_ROUTE = 50;                                          // 每个路由的默认最大连接数
    public static final int                 DEFAULT_MAX_TOTAL     = 100;                                         // 连接池里的最大连接数

    public static final String              DEFAULT_ENCODING      = "UTF-8";

    public static final CloseableHttpClient httpClient;

    static {
        PoolingHttpClientConnectionManager poolingClientConnectionManager = new PoolingHttpClientConnectionManager();
        poolingClientConnectionManager.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
        poolingClientConnectionManager.setMaxTotal(DEFAULT_MAX_TOTAL);

        httpClient = HttpClients.custom().setConnectionManager(poolingClientConnectionManager).build();
    }

    /**
     * 带参数的Http-Post请求
     */
    public static String post(String remoteUrl, Map<String, String> params) {

        if (StringUtils.isEmpty(remoteUrl)) {
            throw new RuntimeException("post remoteUrl not null !");
        }

        logger.info("http client post method, url：{}, params:{}", remoteUrl, params);

        String result = null;
        try {
            HttpPost httpPost = new HttpPost(remoteUrl);
            List<NameValuePair> nameValuePairList = null;
            if (params != null && params.size() > 0) {
                nameValuePairList = new ArrayList<NameValuePair>();

                for (Iterator<Map.Entry<String, String>> entryIterator = params.entrySet().iterator(); entryIterator.hasNext();) {
                    Map.Entry<String, String> entry = entryIterator.next();
                    String key = entry.getKey();
                    String value = entry.getValue();
                    nameValuePairList.add(new BasicNameValuePair(key, value));

                }
                httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairList, DEFAULT_ENCODING));
            }

            HttpClient httpClient = getHttpClient();
            HttpResponse response = httpClient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity());

            logger.info("http client post method, response:{}", result);
        } catch (Exception e) {
            logger.error("http client post error , e {}", e);
            throw new RuntimeException("connect server error!");
        }
        return result;
    }

    /**
     * 无参数的Http-Post请求
     */
    public static String post(String remoteUrl) {
        return post(remoteUrl, null);
    }

    /**
     * 无参数或remoteUrl已带参数的Http-Post请求
     */
    public static String get(String url) {
        return get(url, null);
    }

    public static String get(String url, Map<String, String> headers) {
        HttpGet httpGet = new HttpGet(url);
        if (headers != null && headers.size() > 0) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpGet.setHeader(entry.getKey(), entry.getValue());
            }
        }

        return retrieveResult(httpGet, url);
    }

    private static String retrieveResult(HttpGet httpGet, String url) {
        String result = "";
        try {
            HttpResponse response = getHttpClient().execute(httpGet);
            result = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            logger.error("execute get error , url : {}, exception : {}", url, e);
        } finally {
            httpGet.releaseConnection();
        }

        return result;
    }

    public static String jsonGet(String url) {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("X-Requested-With", "XMLHttpRequest");

        return retrieveResult(httpGet, url);
    }

    public static InputStream downLoadFile(String url) {
        InputStream input = null;
        HttpGet httpGet = new HttpGet(url);
        try {
            HttpResponse response = getHttpClient().execute(httpGet);
            input = response.getEntity().getContent();
        } catch (IOException e) {
            logger.error("execute get error , url : {}, exception : {}", url, e);
        } finally {
            httpGet.releaseConnection();
        }
        return input;
    }

    public static String postJsonBody(String url, Map<String, String> headers, String jsonBody) {
        HttpPost httpPost = new HttpPost(url);
        if(!CollectionUtils.isEmpty(headers)) {
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                httpPost.setHeader(entry.getKey(), entry.getValue());
            }
        }
        if(StringUtils.isNotEmpty(jsonBody)) {
            httpPost.setEntity(new StringEntity(jsonBody, Charset.forName("UTF-8")));
        }
        try {
            HttpResponse response = getHttpClient().execute(httpPost);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK) {
                return EntityUtils.toString(response.getEntity());
            }
        } catch (IOException e) {
            logger.error("execute get error , url : {}, exception : {}", url, e);
        } finally {
            httpPost.releaseConnection();
        }

        return null;
    }

    public static String postJsonBodyByHttps(String url, Map<String, String> headers, String jsonBody) {
        CloseableHttpClient httpClient = null;
        HttpPost httpPost = new HttpPost(url);
        try {
            httpClient = createSslHttpClient();
            if (httpClient != null) {
                if(!CollectionUtils.isEmpty(headers)) {
                    for (Map.Entry<String, String> entry : headers.entrySet()) {
                        httpPost.setHeader(entry.getKey(), entry.getValue());
                    }
                }
                if(StringUtils.isNotEmpty(jsonBody)) {
                    httpPost.setEntity(new StringEntity(jsonBody, Charset.forName("UTF-8")));
                }

                HttpResponse response = httpClient.execute(httpPost);
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    return EntityUtils.toString(response.getEntity());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpPost.releaseConnection();
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (Exception e) {
               e.printStackTrace();
            }
        }

        return null;
    }

    public static String getByHttps(String url, Map<String, String> headers) {
        CloseableHttpClient httpClient = null;
        HttpGet httpGet = new HttpGet(url);
        try {
            httpClient = createSslHttpClient();
            if (httpClient != null) {
                if (headers != null && headers.size() > 0) {
                    for (Map.Entry<String, String> entry : headers.entrySet()) {
                        httpGet.setHeader(entry.getKey(), entry.getValue());
                    }
                }

                HttpResponse response = httpClient.execute(httpGet);
                if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                    return EntityUtils.toString(response.getEntity());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpGet.releaseConnection();
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    private static CloseableHttpClient createSslHttpClient() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
            return HttpClients.custom().setSSLSocketFactory(sslSocketFactory).build();
        } catch(Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    public static HttpClient getHttpClient() {
        return httpClient;
    }

}
